﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Protocolo.Enums;
using Protocolo.Mensajes.Request;
using Protocolo.Mensajes.Response;

namespace Protocolo
{
    public abstract class MensajeBase
    {
        public TipoMensajeEnum Header { get; set; }
        public ComandoEnum Cmd { get; set; }
        protected int Largo
        {
            get
            {
                return Datos.Length;
            }
        }
        protected abstract string Datos { get; set; }

        public void EnviarUDP(string ip, int puerto)
        {
            ComunicacionUDP.EnviarMensajeUDP(this.ToString(), ip, puerto);
        }

        public void EnviarBroadcast(int puertoUDP)
        {
            ComunicacionUDP.EnviarBroadcastUDP(this.ToString(), puertoUDP);
        }

        public void RecibirBroadcast(int puertoUDP)
        {
            string mensaje = ComunicacionUDP.RecibirMensajeUDP(puertoUDP);

            TipoMensajeEnum header = (TipoMensajeEnum)Enum.Parse(typeof(TipoMensajeEnum), mensaje.Substring(0, 3), true);
            ComandoEnum cmd = (ComandoEnum)Enum.Parse(typeof(ComandoEnum), mensaje.Substring(3, 2));

            if (this.Header == header && this.Cmd == cmd)
            {
                this.Datos = mensaje.Substring(10);

                if (!ValidarMensaje(mensaje, this))
                    throw new Exception("El formato del mensaje recibido es incorrecto");
            }
            else
                RecibirBroadcast(puertoUDP);
        }

        protected static bool ValidarMensaje(string strMensaje, MensajeBase mensaje)
        {
            return (strMensaje.Substring(0, 3) == mensaje.Header.ToString()) &&
                   (strMensaje.Substring(3, 2) == ((int)mensaje.Cmd).ToString("00")) &&
                   (strMensaje.Substring(5, 5) == mensaje.Largo.ToString("00000")) &&
                   (strMensaje.Substring(10).Length == mensaje.Largo);
        }

        public static MensajeBase ParsearMensaje(string mensaje)
        {
            MensajeBase retMensaje = null;
           
            TipoMensajeEnum header = (TipoMensajeEnum)Enum.Parse(typeof(TipoMensajeEnum), mensaje.Substring(0, 3), true);
            ComandoEnum cmd = (ComandoEnum)Enum.Parse(typeof(ComandoEnum), mensaje.Substring(3, 2), true);

            if (header == TipoMensajeEnum.REQ)
            {
                switch (cmd)
                {
                    case ComandoEnum.DescargarArchivo: retMensaje = new DescargarArchivoRequest();
                        break;
                    case ComandoEnum.SubirArchivo: retMensaje = new SubirArchivoRequest();
                        break;
                    case ComandoEnum.DescubrirServidor: retMensaje = new DescubrirServidorRequest();
                        break;
                    case ComandoEnum.DescubrirServidorActivos: retMensaje = new DescubrirServidoresRequest();
                        break;
                    case ComandoEnum.EnviarDatosServidor: retMensaje = new EnviarDatosServidorRequest();
                        break;
                    default: throw new Exception(string.Format("Mensaje desconocido: {0} - {1}", header, cmd));
                }
            }
            else if (header == TipoMensajeEnum.RES)
            {
                switch (cmd)
                {
                    case ComandoEnum.DescargarArchivo: retMensaje = new DescargarArchivoResponse();
                        break;
                    case ComandoEnum.SubirArchivo: retMensaje = new SubirArchivoResponse();
                        break;
                    case ComandoEnum.DescubrirServidor: retMensaje = new DescubrirServidorResponse();
                        break;
                    default: throw new Exception(string.Format("Mensaje desconocido: {0} - {1}", header, cmd));
                }
            }
            else
            {
                throw new Exception(string.Format("Mensaje desconocido: {0} - {1}", header, cmd));
            }


            retMensaje.Datos = mensaje.Substring(10);

            if (!ValidarMensaje(mensaje, retMensaje))
                throw new Exception("El formato del mensaje recibido es incorrecto");

            return retMensaje;
        }

        public override string ToString()
        {
            return Header.ToString() + ((int)Cmd).ToString("00") + Largo.ToString("00000") + Datos;
        }
    }
}
